using System.IO.Compression;
using Minio;
using Minio.DataModel.Args;
using Microsoft.Extensions.Options;
using System.Text.RegularExpressions; 
using System.Collections.Concurrent;
using Microsoft.Extensions.Logging;
using System.Text;
using System.Text.Json;
using System.Security.Cryptography;
using Minio.Exceptions;
using System.Threading.Tasks;
using System.IO;
using System.Collections.Generic;
using System;
using System.Threading;
using System.Linq;
using Volo.Abp.DependencyInjection;

/// <summary>
/// 表示 Minio 文件下载服务的命名空间
/// </summary>
namespace Wiz.Minio.EventData;

/// <summary>
/// 启动任务结果
/// </summary>
public class StartTaskResult{
    /// <summary>
    /// 是否成功
    /// </summary>
    public bool IsSuccess{get;set;}
    /// <summary>
    /// 任务Id
    /// </summary>
    public string TaskId{get;set;}
    /// <summary>
    /// 如果不成功，提示消息
    /// </summary>
    public string Message{get;set;}

    private StartTaskResult(){}

    /// <summary>
    /// 启动任务成功
    /// </summary>
    /// <param name="taskId">任务Id</param>
    /// <returns></returns>
    public static StartTaskResult Success(string taskId){
        return new StartTaskResult{
            IsSuccess = true,
            TaskId = taskId
        };
    }

    /// <summary>
    /// 启动任务失败
    /// </summary>
    /// <param name="message">失败消息</param>
    /// <returns></returns>
    public static StartTaskResult Failed(string message){
        return new StartTaskResult{
            IsSuccess = false,
            Message = message
        };
    }
}

/// <summary>
/// 表示 Minio 文件服务的接口
/// </summary>
public interface IMinioDownloadService
{
    /// <summary>
    /// 异步下载并压缩文件
    /// </summary>
    /// <param name="dto">Minio 查询数据传输对象</param>
    /// <returns>开始任务结果</returns>
    /// <remark>
    /// 此方法会返回一个文件流，该流包含了下载任务压缩后的文件内容。
    /// 调用者需要负责关闭该流。
    /// 如果任务未完成，该方法会一直阻塞，直到任务完成。
    /// 如果任务已完成，该方法会返回一个已完成的任务流。
    /// 如果任务不存在或下载任务失败，该方法会抛出异常。
    /// </remark>
    Task<StartTaskResult> StartDownloadTaskAsync(MinioQueryDto dto);
    /// <summary>
    /// 获取任务状态
    /// </summary>
    /// <param name="taskId">任务 ID</param>
    /// <param name="message">任务错误消息</param>
    /// <returns>任务状态</returns>
    DownloadTaskStatus GetTaskStatus(string taskId, out string message);
    /// <summary>
    /// 获取下载任务压缩文件的流
    /// </summary>
    /// <param name="taskId">任务 ID</param>
    /// <param name="cancellationToken"></param>
    /// <returns>文件流</returns>
    Task<Stream> GetTaskStreamAsync(string taskId, CancellationToken cancellationToken);

    
    /// <summary>
    /// 获取所有任务
    /// </summary>
    /// <returns>任务字典</returns>
    Dictionary<string,MinioDownloadTask> GetTasks();

    /// <summary>
    /// 移除任务
    /// </summary>
    /// <param name="taskId">任务 ID</param>
    void RemoveTask(string taskId);

    /// <summary>
    /// 任务状态改变事件
    /// </summary>
    event EventHandler<TaskStatusChangedEventArgs> TaskStatusChanged;
    /// <summary>
    /// 任务进度改变事件
    /// </summary>
    event EventHandler<TaskProgressChangedEventArgs> TaskProgressChanged;
}

/// <summary>
/// Minio 文件服务类，实现了 IDisposable 接口，用于管理 Minio 文件的下载和压缩操作，同时包含清理过期任务的功能。
/// </summary>
public class MinioDownloadService : IMinioDownloadService, IDisposable, ISingletonDependency
{
    /// <summary>
    /// 静态定时器，用于定期清理过期的任务缓存和临时文件
    /// </summary>
    private static Timer _cleanupTimer;
    /// <summary>
    /// 静态同步锁，用于确保定时器操作的线程安全
    /// </summary>
    private static readonly object _timerLock = new();
    /// <summary>
    /// 静态正则表达式，用于匹配特定格式的代码
    /// </summary>
    private static readonly Regex _codeRegex = new Regex(@"(\d{4})-(\d{2})-(\d{2})_(\d{6})", RegexOptions.Compiled);
    
    /// <summary>
    /// 静态并发字典，用于缓存 Minio 下载任务，键为任务 ID，值为任务对象
    /// </summary>
    private static readonly ConcurrentDictionary<string, MinioDownloadTask> _taskCache = new();
    /// <summary>
    /// 下载任务选项
    /// </summary>
    private readonly TaskAppOptions _taskAppOptions;
    /// <summary>
    /// 临时下载目录，位于系统临时目录下的 minio_downloads 文件夹
    /// </summary>
    private readonly string _tempDir = Path.Combine(Path.GetTempPath(), "minio_downloads");
    /// <summary>
    /// 日志记录器，用于记录服务运行过程中的信息
    /// </summary>
    private readonly ILogger<MinioDownloadService> _logger;
    /// <summary>
    /// Minio 客户端工厂，用于创建 Minio 客户端实例
    /// </summary>
    private readonly IMinioClientFactory _minioClientFactory;
    /// <summary>
    /// 任务状态改变事件，当任务状态发生变化时触发
    /// </summary>
    public event EventHandler<TaskStatusChangedEventArgs> TaskStatusChanged;
    /// <summary>
    /// 任务进度改变事件，当任务进度发生变化时触发
    /// </summary>
    public event EventHandler<TaskProgressChangedEventArgs> TaskProgressChanged;
    /// <summary>
    /// 标识对象是否已被释放
    /// </summary>
    private bool _disposed;





    /// <summary>
    /// 构造函数，初始化 Minio 文件服务
    /// </summary>
    /// <param name="options">Minio 配置选项</param>
    /// <param name="logger">日志记录器</param>
    /// <param name="minioClientFactory">Minio 客户端工厂</param>
    public MinioDownloadService(IOptions<TaskAppOptions> taskAppOptions, ILogger<MinioDownloadService> logger, IMinioClientFactory minioClientFactory)
    {
       
        _taskAppOptions = taskAppOptions.Value;
        if (_taskAppOptions.TaskKeepHours < 1){
            _taskAppOptions.TaskKeepHours = 24;
        }

        if (_taskAppOptions.TimerInterval < 1){
            _taskAppOptions.TimerInterval = 10;
        }
        if (_taskAppOptions.RemoveDelay < 1){
            _taskAppOptions.RemoveDelay = 10;
        }
        _logger = logger;
        _minioClientFactory = minioClientFactory;
        // 创建临时下载目录
        Directory.CreateDirectory(_tempDir);
        // 记录临时目录创建信息
        _logger.LogInformation("临时目录已创建: {TempDir}", _tempDir);
        // 确保只创建一次定时器
        if (_cleanupTimer == null)
        {
            // 使用锁确保线程安全
            lock (_timerLock)
            {
                // 如果定时器未创建，则创建定时器
                _cleanupTimer ??= CreateCleanupTimer();
            }
        }
    }

    /// <summary>
    /// 析构函数，在对象被垃圾回收时调用
    /// </summary>
    ~MinioDownloadService()
    {
        // 调用受保护的 Dispose 方法，释放非托管资源
        Dispose(false);
    }

    /// <summary>
    /// 实现 IDisposable 接口的 Dispose 方法，用于释放资源
    /// </summary>
    public void Dispose()
    {
        // 调用受保护的 Dispose 方法，释放托管和非托管资源
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// 受保护的 Dispose 方法，用于释放资源
    /// </summary>
    /// <param name="disposing">是否释放托管资源</param>
    protected virtual void Dispose(bool disposing)
    {
        // 如果对象已经被释放，则直接返回
        if (_disposed) return;
        // 如果正在释放托管资源
        if (disposing)
        {
            // 这里可以添加释放托管资源的代码
        }
        // 使用锁确保线程安全
        lock (_timerLock)
        {
            // 如果定时器存在
            if(_cleanupTimer != null){
                // 释放定时器资源
                _cleanupTimer?.Dispose();
                _cleanupTimer = null;
                _logger.LogInformation("定时器已释放");
            }
        }
        // 标记对象已被释放
        _disposed = true;
    }

    

    /// <summary>
    /// 生成任务 ID
    /// </summary>
    /// <param name="queryDto">查询数据传输对象</param>
    /// <returns>生成的任务 ID</returns>
    private string GenerateTaskId(string queryDto)
    {
        // 使用 MD5 算法创建哈希对象
        using var md5 = MD5.Create();
        // 计算查询数据的哈希值
        var hash = md5.ComputeHash(Encoding.UTF8.GetBytes(queryDto));
        // 将哈希值转换为十六进制字符串
        return BitConverter.ToString(hash).Replace("-", "").ToLower();
    }

    /// <summary>
    /// 获取对象文件路径
    /// </summary>
    /// <param name="dto">Minio 查询数据传输对象</param>
    /// <returns>对象文件路径字典</returns>
    private bool TryGetObjectFilePath(MinioQueryDto dto, out List<MinioFilePathInfo> result, out string message){
        // 创建一个空的字典，用于存储对象文件路径
        result = new List<MinioFilePathInfo>();
        // 初始化错误消息为空
        message = string.Empty;
        bool success = false;
        // 遍历查询数据中的代码列表
        foreach(var code in dto.Codes){
            // 使用正则表达式匹配代码
            var match = _codeRegex.Match(code);
            if(!match.Success){
                message = $"事件编码 {code} 不符合规范";
                return success;
            }
            var ym = $"{match.Groups[1].Value}{match.Groups[2].Value}";
            var fileName = $"Event_{match.Value}";
            if(dto.System.Equals("ts", StringComparison.InvariantCultureIgnoreCase)){
                fileName += ".hdf";
            }
            else
            {
                fileName += ".txt";
            }
            result.Add(new MinioFilePathInfo{
                MinioBasePath = $"{dto.EventDataDir}/{dto.System}",
                RelativeFilePath = $"{ym}/{dto.Device}",
                FileName = fileName
            });
        }
        
        success = true;
        return success;
    }

    /// <summary>
    /// 获取不存在对象文件
    /// </summary>
    /// <param name="dto">Minio 查询数据传输对象</param>
    private async Task<Dictionary<string,List<string>>> CheckNotExistsObjectAsync(MinioQueryDto dto, List<MinioFilePathInfo> paths)
    {
        var result = new Dictionary<string, List<string>>();
        
        var minio = _minioClientFactory.CreateClient();

        var g = paths.GroupBy(p => p.RelativeFilePath).ToArray();
        var minioBasePath = $"{dto.EventDataDir}/{dto.System}";

        foreach(var item in g)
        {
            var parentKey = $"{minioBasePath}/{item.Key}/";
            var fileNames = item.Select(p => p.FileName).ToList();
            try
            {
                var observable = minio.ListObjectsEnumAsync(new ListObjectsArgs()
                .WithBucket(dto.DataSource)
                .WithPrefix(parentKey))
                .ConfigureAwait(false);

                await foreach(var obj in observable)
                {
                    var fileName = Path.GetFileName(obj.Key);
                    if (fileNames.Contains(fileName, StringComparer.InvariantCultureIgnoreCase))
                    {
                        fileNames.RemoveAll(p => p.Equals(fileName, StringComparison.InvariantCultureIgnoreCase));
                    }
                    if(fileNames.Count == 0)
                    {
                        break;
                    }
                }

                if(fileNames.Count > 0)
                {
                    result[parentKey] = fileNames;
                    break;
                }
            }            
            catch (Exception ex)
            {
                _logger.LogError(ex, "检查 {fileName} 在 {path} 是否存在时出错", string.Join(", ", fileNames), parentKey);
                result[parentKey] = fileNames;
                break;
            }
        }
        return result;
    }

    /// <summary>
    /// 异步处理下载任务ar fileName = $"{DataDirPrefix}/json/{dto.System}/{ym}/{code}";
    /// </summary>
    /// <param name="taskId">任务 ID</param>
    /// <param name="dto">Minio 查询数据传输对象</param>
    /// <returns>异步任务</returns>
    private async Task ProcessDownloadAsync(string taskId, MinioQueryDto dto, List<MinioFilePathInfo> filePaths)
    {
        // 尝试从任务缓存中获取任务对象
        if (!_taskCache.TryGetValue(taskId, out var task)) return;
        // 将任务状态设置为运行中
        task.Status = DownloadTaskStatus.Running;
        // 触发任务状态改变事件
        TaskStatusChanged?.Invoke(this, new TaskStatusChangedEventArgs
        {
            TaskId = taskId,
            Status = DownloadTaskStatus.Running
        });
        // 初始化任务状态为成功
        var status = DownloadTaskStatus.Success;
        // 初始化错误消息为空
        var message = string.Empty;
        // 构建临时下载目录
        var tempDir = Path.Combine(_tempDir, taskId);
        // 构建压缩文件路径
        var zipPath = Path.Combine(_tempDir, $"{taskId}.zip");
        // 如果压缩文件已存在
        if (File.Exists(zipPath))
        {
            task.FilePath = zipPath;
            task.EndTime = DateTime.UtcNow;
            // 将任务状态设置为成功
            task.Status = DownloadTaskStatus.Success;
            // 触发任务状态改变事件
            TaskStatusChanged?.Invoke(this, new TaskStatusChangedEventArgs
            {
                TaskId = taskId,
                Status = DownloadTaskStatus.Success
            });
            if (task.Progress != 100)
            {
                task.Progress = 100;
                TaskProgressChanged?.Invoke(this, new TaskProgressChangedEventArgs
                {
                    TaskId = taskId,
                    Progress = 100
                });
            }
            return;
        }



        try
        {
            // 创建 Minio 客户端实例
            var minio = _minioClientFactory.CreateClient();
            // 创建临时下载目录
            Directory.CreateDirectory(tempDir);

            // 定义对象路径和目标路径变量
            string destPath;
            // 定义计数器和总对象数
            var count = 0;
            var hasFile = false;
            var total = filePaths.Count;
            var objects = new List<string>();

            var minioBasePath = $"{dto.EventDataDir}/{dto.System}";
            var g = filePaths.GroupBy(p => p.RelativeFilePath);
            
            // 遍历对象文件路径字典
            foreach (var item in g)
            {
                
                objects.Clear();
                var parentKey = $"{minioBasePath}/{item.Key}/";
                var fileNames = item.Select(p => p.FileName).ToArray();
                try
                {
                    var observable = minio.ListObjectsEnumAsync(new ListObjectsArgs()
                    .WithBucket(dto.DataSource)
                    .WithPrefix(parentKey)
                    .WithRecursive(true)
                    )                    
                    .ConfigureAwait(false);

                    await foreach (var obj in observable)
                    {
                        var fileName = Path.GetFileName(obj.Key);
                        if (fileNames.Contains(fileName, StringComparer.InvariantCultureIgnoreCase))
                        {
                            objects.Add(obj.Key);
                        }
                    }
                    var foundFiles = objects.Select(p => Path.GetFileName(p)).Distinct().ToArray();
                    var notFoundFiles = fileNames.Except(foundFiles, StringComparer.InvariantCultureIgnoreCase).ToArray();
                    if (notFoundFiles.Length > 0)
                    {
                        if (!_taskAppOptions.SkipNotFound)
                        {
                            // 将任务状态设置为失败
                            status = DownloadTaskStatus.Failed;
                            // 记录错误消息
                            message = $"在 {minioBasePath}/{item.Key} 中没有找到文件: {string.Join(", ", notFoundFiles)}";
                            // 记录下载失败日志
                            _logger.LogError("在 {basePath} 中没有找到文件: {ObjectPath}", $"{minioBasePath}/{item.Key}", string.Join(", ", notFoundFiles));
                            // 跳出循环
                            break;
                        }
                        else
                        {
                            _logger.LogWarning("在 {basePath} 中没有找到文件: {ObjectPath}", $"{minioBasePath}/{item.Key}", string.Join(", ", notFoundFiles));
                        }
                    }                    
                }
                catch (Exception ex)
                {
                    if (!_taskAppOptions.SkipNotFound)
                    {
                        // 将任务状态设置为失败
                        status = DownloadTaskStatus.Failed;
                        // 记录错误消息
                        message = ex.Message;
                        // 记录下载失败日志
                        _logger.LogError("在 {basePath} 查找文件失败: {ObjectPath}", $"{minioBasePath}/{item.Key}", string.Join(", ", fileNames));
                        // 跳出循环
                        break;
                    }
                    else
                    {
                        _logger.LogWarning("在 {basePath} 查找文件失败: {ObjectPath}", $"{minioBasePath}/{item.Key}", string.Join(", ", fileNames));
                    }
                }


                foreach (var objectPath in objects)
                {
                    destPath = Path.Combine(tempDir, objectPath.Substring(minioBasePath.Length + 1));
                    
                    var folder = Path.GetDirectoryName(destPath);
                    if(!Directory.Exists(folder)){
                        Directory.CreateDirectory(folder);
                    }
                    
                    try
                    {
                        // 异步从 Minio 下载对象到本地文件
                        await minio.GetObjectAsync(
                            new GetObjectArgs()
                                .WithBucket(dto.DataSource)
                                .WithObject(objectPath)
                                .WithFile(destPath)
                        )
                        .ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        if (!_taskAppOptions.SkipNotFound)
                        {
                            // 将任务状态设置为失败
                            status = DownloadTaskStatus.Failed;
                            // 记录错误消息
                            message = ex.Message;
                            // 记录下载失败日志
                            _logger.LogError(ex, "下载失败: {ObjectPath}", objectPath);
                            // 跳出循环
                            break;
                        }
                        else
                        {
                            _logger.LogWarning(ex, "下载失败: {ObjectPath}", objectPath);
                        }
                    }
                }
                if (status == DownloadTaskStatus.Failed)
                {
                    break;
                }
                hasFile = true;
                var process = ++count * 100 / total;
                if (task.Progress != process)
                {
                    task.Progress = process;
                    TaskProgressChanged?.Invoke(this, new TaskProgressChangedEventArgs
                    {
                        TaskId = taskId,
                        Progress = process
                    });
                }
            }

            if (!hasFile && status != DownloadTaskStatus.Failed)
            {
                status = DownloadTaskStatus.Failed;
                message = "没有获取到文件";
            }
            // 如果任务状态为成功
            if (status == DownloadTaskStatus.Success)
            {
                try
                {
                    // 将临时下载目录压缩为 ZIP 文件
                    ZipFile.CreateFromDirectory(tempDir, zipPath);
                    // 将压缩文件路径赋值给任务对象
                    task.FilePath = zipPath;
                }
                catch (Exception ex)
                {
                    // 将任务状态设置为失败
                    status = DownloadTaskStatus.Failed;
                    // 记录错误消息
                    message = ex.Message;
                    // 记录压缩文件失败日志
                    _logger.LogError(ex, "压缩文件失败");
                    // 如果压缩文件已存在
                    if (File.Exists(zipPath))
                    {
                        try
                        {
                            File.Delete(zipPath);
                        }
                        catch (Exception ex2)
                        {
                            _logger.LogError(ex2, "删除文件失败: {file}", zipPath);
                        }
                    }
                }
            }

        }
        catch (Exception ex)
        {
            // 将任务状态设置为失败
            status = DownloadTaskStatus.Failed;
            message = ex.Message;
        }
        finally
        {
            // 记录任务结束时间
            task.EndTime = DateTime.UtcNow;
            try
            {
                // 删除临时下载目录
                Directory.Delete(tempDir, true);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "删除临时目录失败: {TempDir}", tempDir);
            }
        }

        // 更新任务状态
        task.Status = status;
        // 更新任务错误消息
        task.ErrorMessage = message;
        // 触发任务状态改变事件
        TaskStatusChanged?.Invoke(this, new TaskStatusChangedEventArgs
        {
            TaskId = taskId,
            Status = status,
            ErrorMessage = message
        });
    }

    /// <summary>
    /// 异步下载并压缩文件
    /// </summary>
    /// <param name="dto">Minio 查询数据传输对象</param>
    /// <returns>任务 ID</returns>
    public async Task<StartTaskResult> StartDownloadTaskAsync(MinioQueryDto dto)
    {
        if(dto.Codes == null || dto.Codes.Length == 0){
            return StartTaskResult.Failed("没有指定实验编码");
        }

        dto.Codes = dto.Codes.Distinct().OrderBy(x => x).ToArray();

        // 将查询数据序列化为 JSON 字符串
        var json = JsonSerializer.Serialize(dto, new JsonSerializerOptions 
        { 
            // 使用驼峰命名策略
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
            // 不进行缩进格式化
            WriteIndented = false 
        });

        // 生成任务 ID
        var taskId = GenerateTaskId(json);
        // 尝试从任务缓存中获取任务对象
        if(_taskCache.TryGetValue(taskId, out var task)){
            // 如果任务状态不是失败
            if( task.Status != DownloadTaskStatus.Failed)
            {
                // 直接返回任务 ID
                return StartTaskResult.Success(taskId);
            }
        }

        if(!TryGetObjectFilePath(dto, out var filePaths, out var message)){
            return StartTaskResult.Failed(message);
        }

        if(filePaths.Count == 0){
            return StartTaskResult.Failed("没有找到文件");
        }
        if (!_taskAppOptions.SkipNotFound){          
            var notExists = await CheckNotExistsObjectAsync(dto, filePaths);
            if(notExists.Count > 0){
                var kv = notExists.First();
                return StartTaskResult.Failed($"文件 {string.Join(", ", kv.Value)} 在 {kv.Key} 中不存在");
            }   
        }
        
        // 创建新的任务对象
        task = new MinioDownloadTask
        {
            // 将任务状态设置为待处理
            Status = DownloadTaskStatus.Pending,
            // 设置任务查询数据
            QueryDto = json,
            // 记录任务开始时间
            StartTime = DateTime.UtcNow,
            // 计算任务过期时间
            ExpireTime = DateTime.UtcNow.Add(TimeSpan.FromHours(_taskAppOptions.TaskKeepHours))
        };
        // 将任务对象添加到任务缓存中
        _taskCache[taskId] = task;
    
        
        // 启动后台任务处理下载和压缩操作
        _ = Task.Run(async () => await ProcessDownloadAsync(taskId, dto, filePaths));
        // 返回任务 ID
        return StartTaskResult.Success(taskId);
    }

    
    /// <summary>
    /// 移除任务
    /// </summary>
    /// <param name="taskId">任务 ID</param>    
    public void RemoveTask(string taskId){
        if(_taskCache.TryGetValue(taskId, out var task)){
            task.ExpireTime = DateTime.UtcNow.AddMinutes(_taskAppOptions.RemoveDelay);
        }
      }
    /// <summary>
    /// 获取任务状态
    /// </summary>
    /// <param name="taskId">任务 ID</param>
    /// <param name="message">任务错误消息</param>
    /// <returns>任务状态</returns>
    public DownloadTaskStatus GetTaskStatus(string taskId, out string message)
    {
        message = string.Empty;
        // 尝试从任务缓存中获取任务对象
        if (!_taskCache.TryGetValue(taskId, out var task))
        {
            // 设置错误消息为任务不存在
            message = "任务不存在";
            // 返回任务状态为失败
            return DownloadTaskStatus.Failed;
        }
        // 获取任务错误消息
        message = task.ErrorMessage;                
        // 返回任务状态
        return task.Status;
    }

    /// <summary>
    /// 获取所有任务
    /// </summary>
    /// <returns>任务字典</returns>
    public Dictionary<string,MinioDownloadTask> GetTasks(){
        return _taskCache.ToDictionary(kv => kv.Key, kv => kv.Value);
    }

    /// <summary>
    /// 获取下载任务压缩文件的流
    /// </summary>
    /// <param name="taskId">任务 ID</param>
    /// <param name="cancellationToken"></param>
    /// <returns>文件流</returns>
    public async Task<Stream> GetTaskStreamAsync(string taskId, CancellationToken cancellationToken)
    {
        MinioDownloadTask task = null;
        bool finished = false;
        while(!finished){
            // 尝试从任务缓存中获取任务对象
            if (!_taskCache.TryGetValue(taskId, out task))
            {
                // 如果任务不存在，抛出文件未找到异常
                throw new FileNotFoundException("任务不存在或已过期");
            }
            
            cancellationToken.ThrowIfCancellationRequested();

            switch(task.Status){
                case DownloadTaskStatus.Pending:
                case DownloadTaskStatus.Running:
                    await Task.Delay(5000); 
                    break;
                case DownloadTaskStatus.Success:
                    finished = true;
                    break;
                case DownloadTaskStatus.Failed:
                    throw new Exception($"下载失败: {task.ErrorMessage}"); 
            }
        }

        return File.OpenRead(task.FilePath);
        
    }

    /// <summary>
    /// 创建清理过期任务的定时器
    /// </summary>
    /// <returns>定时器对象</returns>
    private Timer CreateCleanupTimer()
    {
        // 记录启动缓存清理定时器的信息
        _logger.LogInformation("启动缓存清理定时器，间隔：{TimerInterval}分钟", _taskAppOptions.TimerInterval);
        // 创建一个定时器
        return new Timer(_ => 
        {
            // 查找所有过期的任务键
            var expiredKeys = _taskCache
                .Where(kv => DateTime.UtcNow > kv.Value.ExpireTime)
                .Select(kv => kv.Key)
                .ToList();

            // 移除所有过期的任务
            foreach (var key in expiredKeys)
            {
                _taskCache.TryRemove(key, out var _);              
            }
            // 获取临时目录的 DirectoryInfo 对象
            var zipDir = new DirectoryInfo(_tempDir);
            // 如果临时目录存在
            if(zipDir.Exists){
                // 遍历临时目录下的所有 ZIP 文件
                foreach (var file in zipDir.GetFiles("*.zip"))
                {
                    // 获取 ZIP 文件对应的任务键
                    var key = file.Name.Replace(".zip", "");
                    // 如果任务键不存在于任务缓存中
                    if (!_taskCache.ContainsKey(key))
                    {
                        try
                        {
                            // 删除 ZIP 文件
                            file.Delete();
                        }
                        catch
                        {
                           
                        }
                    }
                }
                foreach (var dir in zipDir.GetDirectories())
                {
                    var key = dir.Name;
                    if (!_taskCache.ContainsKey(key))
                    {
                        try
                        {
                            dir.Delete(true);
                        }
                        catch
                        {

                        }
                    }
                }
            }
        }, null, TimeSpan.FromMinutes(_taskAppOptions.TimerInterval), TimeSpan.FromMinutes(_taskAppOptions.TimerInterval));
    }
}